package com.aleyn.router.plug.visitor

import com.aleyn.router.plug.data.HandleModel
import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.ClassNode

/**
 * @author : Aleyn
 * @date : 2023/07/30 : 22:33
 *
 * ASM ClassNode, 用于在字节码扫描期间识别和提取 LRouter 相关注解的信息。
 *
 * 这个类是 `LRouterClassTask` 扫描阶段的核心处理器。
 * 它继承自 `ClassNode`，这使得它可以方便地访问一个类的所有信息，包括类名、注解、实现的接口等。
 *
 * 主要职责是：
 * 1.  **识别特定后缀的类**：检查类名是否以 `__LRouter$$Autowired` 或 `__ModuleRouter__Registered` 结尾，这些是 KSP 生成的辅助类。
 * 2.  **识别拦截器 (Interceptor)**：检查类是否同时被 `@Interceptor` 注解标记并实现了 `LRouterInterceptor` 接口。
 * 3.  **识别初始化器 (Initializer)**：检查类是否同时被 `@Initializer` 注解标记并实现了 `LRouterInitializer` 接口。
 *
 * 当识别到符合条件的类时，它会提取相关信息（如类名、优先级、是否异步等），
 * 并创建一个对应的 `HandleModel` 子类实例（`Autowired`, `Module`, `Intercept`, `Initializer`），
 * 然后将该实例添加到 `outModel` 列表中，以供后续处理。
 *
 * @param outModel 用于收集所有被识别到的注解信息的输出列表。
 */

/**
 * KSP 为 `@Autowired` 注解生成的辅助类的通用后缀。
 */
internal const val AUTOWIRED_CLASS_SUFFIX = "__LRouter\$\$Autowired"

/**
 * KSP 为每个模块生成的路由表注册类的通用后缀。
 */
internal const val MODULE_ROUTER_CLASS_SUFFIX = "__ModuleRouter__Registered"

/**
 * ASM ClassVisitor，用于查找被 LRouter 相关注解标记的类。
 * @param outModel 用于存储扫描结果的列表。
 */
class FindHandleClass(private val outModel: ArrayList<HandleModel>) : ClassNode(Opcodes.ASM9) {

    /**
     * 访问类的头部信息。
     * 这里我们只是调用父类实现，主要的信息处理在 `visitEnd` 中完成。
     */
    override fun visit(
        version: Int,
        access: Int,
        name: String?,
        signature: String?,
        superName: String?,
        interfaces: Array<out String>?
    ) {
        super.visit(version, access, name, signature, superName, interfaces)
    }

    /**
     * 在访问完类的所有部分后被调用。
     *
     * 这是进行注解识别和信息提取的核心逻辑所在。
     * `ClassNode` 在此时已经收集了类的所有信息（注解、接口等）。
     */
    override fun visitEnd() {
        // 1. 检查是否为 KSP 生成的 Autowired 辅助类
        if (name.endsWith(AUTOWIRED_CLASS_SUFFIX)) {
            outModel.add(HandleModel.Autowired(name))
            return
        }
        // 2. 检查是否为 KSP 生成的模块路由表注册类
        if (name.endsWith(MODULE_ROUTER_CLASS_SUFFIX)) {
            outModel.add(HandleModel.Module(name))
            return
        }

        // 3. 检查是否为拦截器 (Interceptor)
        // 获取类上的 @Interceptor 注解
        val interceptorAnn =
            invisibleAnnotations?.firstOrNull { it.desc == "Lcom/aleyn/annotation/Interceptor;" }

        // 检查类是否实现了 LRouterInterceptor 接口
        val routerIntercept =
            interfaces?.firstOrNull { it == "com/aleyn/router/core/LRouterInterceptor" }

        // 如果同时满足注解和接口条件，则判定为拦截器
        if (!interceptorAnn?.desc.isNullOrBlank() && !routerIntercept.isNullOrBlank()) {
            // 从注解中提取 priority 属性值
            val priority = (interceptorAnn?.values?.getOrNull(1) as? Byte) ?: 0
            outModel.add(HandleModel.Intercept(priority, name))
            return
        }

        // 4. 检查是否为初始化器 (Initializer)
        // 获取类上的 @Initializer 注解
        val initAnn = invisibleAnnotations?.firstOrNull {
            it.desc == "Lcom/aleyn/annotation/Initializer;"
        }
        // 检查类是否实现了 LRouterInitializer 接口
        val routerInitializer = interfaces?.firstOrNull {
            it == "com/aleyn/router/core/LRouterInitializer"
        }

        // 如果同时满足注解和接口条件，则判定为初始化器
        if (!initAnn?.desc.isNullOrBlank() && !routerInitializer.isNullOrBlank()) {
            var priority: Byte = 0
            var async = false
            // 从注解中提取 priority 和 async 属性值
            initAnn!!.values?.forEachIndexed { index, any ->
                if (index % 2 == 1) return@forEachIndexed
                if (any == "priority") {
                    priority = (initAnn.values.getOrNull(index + 1) as? Byte) ?: 0
                } else if (any == "async") {
                    async = (initAnn.values.getOrNull(index + 1) as? Boolean) ?: false
                }
            }
            outModel.add(HandleModel.Initializer(priority.toInt(), if (async) 1 else 0, name))
        }
    }

}